package com.fadis.expire;

import com.fadis.FadisLog;
import com.fadis.db.FadisDB;
import com.fadis.FadisThread;
import com.fadis.persist.AOFMgmr;
import com.fadis.utils.SafeEncoder;

import java.util.concurrent.*;

public class ExpireMgmr {

    public static boolean setExpireTime(String key, long lifeTime){
        if(!FadisDB.containsKey(key)){
            return false;
        }
        ExpireInfo e = ExpireInfo.create(lifeTime);
        FadisDB.expireTime.put(key, e);
        return true;
    }

    public static boolean isExpired(String key){
        ExpireInfo e = FadisDB.expireTime.get(key);
        return e != null && e.isExpired();
    }

    public static ExpireInfo get(String key){
        return FadisDB.expireTime.get(key);
    }

    /**
     * 这个方法必须在单线程里调用，默认是这样的
     * @param key
     * @return
     */
    public static boolean checkAndDelete(String key){
        if(isExpired(key)){
//            FadisLog.log("过期删除：" + key);
            FadisDB.remove(key); // 先删掉，防止指令延迟期间key依然被访问
            FadisDB.expireTime.remove(key);
            AOFMgmr.save("del", "*2\r\n$3\r\ndel\r\n$" + SafeEncoder.encode(key).length + "\r\n" + key + "\r\n");
            return true;
        }
        return false;
    }

    public static void touch(String key){
        ExpireInfo e = FadisDB.expireTime.get(key);
        if(e != null) e.touch();
    }

    public static void deleteExpireInfo(String key){
        FadisDB.expireTime.remove(key);
    }

    public static long pttl(String key){
        if(!FadisDB.containsKey(key)) return -2;
        if(!FadisDB.expireTime.containsKey(key)) return -1;
        ExpireInfo e = FadisDB.expireTime.get(key);
        return e.touchTime + e.lifeTime - System.currentTimeMillis();
    }

    public static long ttl(String key){
        long p = pttl(key);
        if(p == -2 || p == -1) return p;
        return p/1000;
    }

    public static int persist(String key){
        if(FadisDB.containsKey(key) && FadisDB.expireTime.containsKey(key)){
            FadisDB.expireTime.remove(key);
            return 1;
        }
        return 0;
    }

    public static void startClearExpiredKeys(){
        // 每隔1秒运行一次，每次运行中每隔10ms清理一个key，del动作要进入单线程，并且要记录日志
        long taskInterval = 1000;
        long keyInterval = 10;
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                clearExpiredKeys(keyInterval);
            }
        }, 0, taskInterval, TimeUnit.MILLISECONDS);
    }

    public static void clearExpiredKeys(long keyInterval){
//        System.out.println("检查缓存。。。");
        for (String k: FadisDB.expireTime.keySet()){
//            System.out.println("检查--" + k);
            // 对key的操作得发送到单线程执行
            final String key = k;
            if(ExpireMgmr.isExpired(k)){
                FadisThread.runInRedisThread(new Callable<Object>() {
                    @Override
                    public Object call() throws Exception {
                        FadisDB.remove(key); // 先删掉，防止指令延迟期间key依然被访问
                        FadisDB.expireTime.remove(key);
                        AOFMgmr.save("del", "*2\r\n$3\r\ndel\r\n$" + SafeEncoder.encode(key).length + "\r\n" + key + "\r\n");
                        return null;
                    }
                });
            }
            try {
                if(keyInterval > 0) Thread.sleep(keyInterval);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
